/* Provide a write function for a class member */

#ifndef MC_ACCESSOR_WRITE_HPP
#define MC_ACCESSOR_WRITE_HPP

#include <cassert>
#include <cstddef>
#include <sstream>

/* TR1 header */
#ifdef __GLIBCXX__
	#include <tr1/type_traits>
#else
	#include <type_traits>
#endif

#include <memchart/exception.hpp>
#include <memchart/type_traits.hpp>
#include <memchart/types.hpp>

namespace memchart
{
	/*
	 * Choose a write implementation depending on T properties.
	 *
	 * IsCvQualified should really be IsConst, but the following code
	 * doesn't seem to work too, so we restrict write access for volatile:
	 *
	 *   volatile int i;
	 *   std::cin >> i;
	 */
	template <bool IsCvQualified, bool IsPointer, bool IsArray,
		typename C, typename T, T C::* M>
	struct accessor_write_impl
	{
		/* Default implementation */
		
		static bool is_writable ()
		{
			return false;
		}
		
		static void write (void * /* p */, const string & /* val */)
		{
			throw conversion_error();
		}
	};

	/* T is not cv-qualified, not a pointer and not an array */
	template <typename C, typename T, T C::* M>
	struct accessor_write_impl<false, false, false, C, T, M>
	{
		static bool is_writable ()
		{
			return true;
		}
	
		static void write (void *p, const string & val)
		{
			assert(p != NULL);

			C & obj = *reinterpret_cast<C *>(p);

			std::istringstream ss(val);

			if (!(ss >> obj.*M))
				throw conversion_error();
		}
	};


	template <typename C, typename T, T C::* M>
	struct accessor_write :
		accessor_write_impl<
				is_cv_qualified<T>::value,
				is_pointer<T>::value,
				std::tr1::is_array<T>::value,
				C, T, M
			>
	{ };
}

#endif /* MC_ACCESSOR_WRITE_HPP */
